package pw.wmgblog.tools.utils;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import org.springframework.util.StringUtils;

import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;

import static com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATES_AS_TIMESTAMPS;

public class JsonUtil {
    // 定义jackson对象
    private static ObjectMapper objectMapper = new ObjectMapper();

    static {
        //对象的所有字段全部列入
        objectMapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);
        //取消默认转换timestamps形式
        objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
        //忽略空Bean转json的错误
        objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        //所有的日期格式都统一为以下的样式，即yyyy-MM-dd HH:mm:ss
        objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
        //忽略 在json字符串中存在，但是在java对象中不存在对应属性的情况。防止错误
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    }

    /**
     * 构造返回结果
     *
     * @param status
     * @param message
     * @param data
     * @return
     */
    public static String generateResult(int status, String message, Object data) {
        try {
            Map map = new HashMap();
            map.put("status", status);
            map.put("message", message);
            if (data != null) {
                map.put("data", data);
            }
            return objectMapper.writeValueAsString(map);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 构造返回结果
     *
     * @param status
     * @param message
     * @param data
     * @param <T>
     * @return
     */
    public static <T> String generateResultPretty(int status, String message, T data) {
        try {
            Map map = new HashMap();
            map.put("status", status);
            map.put("message", message);
            if (data != null) {
                map.put("data", data);
            }
            return objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(map);
        } catch (Exception e) {
            //log.warn("Parse Object to String error",e);
            return null;
        }
    }

    /**
     * obj转json
     *
     * @param obj
     * @param <T>
     * @return
     */
    public static <T> String obj2String(T obj) {
        if (obj == null) {
            return null;
        }
        try {
            return obj instanceof String ? (String) obj : objectMapper.writeValueAsString(obj);
        } catch (Exception e) {
            // log.warn("Parse Object to String error",e);
            return null;
        }
    }

    /**
     * obj->json
     *
     * @param obj
     * @param <T>
     * @return
     */
    public static <T> String obj2StringPretty(T obj) {
        if (obj == null) {
            return null;
        }
        try {
            return obj instanceof String ? (String) obj : objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
        } catch (Exception e) {
            //log.warn("Parse Object to String error",e);
            return null;
        }
    }

    /**
     * json转简单对象
     *
     * @param str
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> T string2Obj(String str, Class<T> clazz) {
        if (StringUtils.isEmpty(str) || clazz == null) {
            return null;
        }
        try {
            return clazz.equals(String.class) ? (T) str : objectMapper.readValue(str, clazz);
        } catch (Exception e) {
            // log.warn("Parse String to Object error",e);
            return null;
        }
    }


    /**
     * json转
     *
     * @param str
     * @param typeReference
     * @param <T>
     * @return {"11":{"key":"key","num":"22"},"key":{"key":"12kk","num":"34"}}--->Map<String,Word>
     * Map<String,Word> mm = string2Obj(string, new TypeReference<Map<String, Word>>() {
     * });
     */
    public static <T> T string2Obj(String str, TypeReference<T> typeReference) {
        if (StringUtils.isEmpty(str) || typeReference == null) {
            return null;
        }
        try {
            return (T) (typeReference.getType().equals(String.class) ? str : objectMapper.readValue(str, typeReference));
        } catch (Exception e) {
            // log.warn("Parse String to Object error",e);
            return null;
        }
    }


    /**
     * @param str
     * @param collectionClass
     * @param elementClasses
     * @param <T>
     * @return Map<String       ,       Word> mm = string2Obj(string, Map.class,String.class,Word.class);
     */
    public static <T> T string2Obj(String str, Class<?> collectionClass, Class<?>... elementClasses) {
        JavaType javaType = objectMapper.getTypeFactory().constructParametricType(collectionClass, elementClasses);
        try {
            return objectMapper.readValue(str, javaType);
        } catch (Exception e) {
            //log.warn("Parse String to Object error",e);
            return null;
        }
    }


    public static void main(String[] args) {
        Map map = new HashMap();
        Word word = new Word();
        word.key = "key";
        word.num = "22";
        map.put("11", word);
        word = new Word();
        word.key = "12kk";
//        word.num = "34";
        map.put("key", word);

        System.out.println(obj2String(map));
        String string = obj2String(map);
        Map<String, Word> mm = string2Obj(string, Map.class, String.class, Word.class);
        System.out.println(mm.size());
        System.out.println(mm.get("key").getKey());
        //System.out.println(toJson(1,"mess",map));
    }
}

class Word {
    public String key;
    public String num;

    public String getKey() {
        return key;
    }

    public void setKey(String key) {
        this.key = key;
    }

    public String getNum() {
        return num;
    }

    public void setNum(String num) {
        this.num = num;
    }
}
